'2008-04-08 DNH refactored this into several different classes.
'One set of classes handle the definition of the stepwise series of jobs to do in a batch.
'One class each handles the calculation job for radial and neighbourhood approaches.
'This form implements a callback interface for progress reports. Could be extended to offer cancellation option one day.


Imports TreeCreeper01Interfaces
Imports TreeCreeper01
Imports TreeCreeper02

Friend Interface IProgressReportRecipient
    Sub ReportProgress(ByVal Description As String)
End Interface

Public Class fSpatialBatchAnalysis

    Implements IProgressReportRecipient

    Private mStudy As IStudySpatial
    Private mDataAgentSpatial As IDataAgentSpatial
    'Private mColouringList As cSpeciesColouringList

    Private Sub ReceiveProgressReport(ByVal Description As String) Implements IProgressReportRecipient.ReportProgress

        LabelProgress.Text = Description
        LabelProgress.Update()
        Refresh()

    End Sub


    Public Sub OfferBatch(ByVal Study As IStudySpatial, ByVal StudyName As String, ByVal DataAgentSpatial As IDataAgentSpatial) ', ByVal ColouringList As cSpeciesColouringList)

        'This is the show window method. Everything else is private

        mStudy = Study
        'mColouringList = ColouringList
        mDataAgentSpatial = DataAgentSpatial

        With mStudy.PlantList
            Me.UpDownInnerRadiusUpperLimit.Maximum = CDec(.MaximumHorizontalOrVerticalSpatialSeparation())
            Me.UpDownOuterRadiusUpperLimit.Maximum = CDec(.MaximumHorizontalOrVerticalSpatialSeparation())
            Me.UpDownRandomDistanceLimit.Maximum = CDec(.MaximumHorizontalOrVerticalSpatialSeparation())
            Me.UpdownNeighboursInnerUpperLimit.Maximum = .Count - 1
            Me.UpdownNeighboursInnerLowerLimit.Maximum = .Count - 1
            Me.UpdownNeighboursOuterUpperLimit.Maximum = .Count - 1
            Me.UpdownNeighboursOuterLowerLimit.Maximum = .Count - 1
            UpDownNeighbourSteps.Minimum = 1
        End With

        If mDataAgentSpatial.SourceFileType = eSourceFileType.eftCSV Then
            Me.CheckDoWriteDetailsToFile.Checked = False
            Me.CheckDoWriteDetailsToFile.Enabled = True
        End If

        Show()

    End Sub

    Private Sub DoSimulation()

        'Start the job. Which one depends on the currently selected tab.

        Dim PrimaryOutputStringBuilder As System.Text.StringBuilder
        Dim PrimaryOutput As IResultsTable
        Dim SecondaryOutput As IResultsTable

        Dim RandomisedPlantLists As Collection
        Dim NumberOfRandoms As Integer
        Dim DoRandomiseWithinGroupsOnly As Boolean
        Dim DistanceLimitedRandomisation As Double
        Dim DetailResultRowComposition As eDetailResultRowComposition

        Dim NeighbourhoodCalculator As cSpatialSimulationJobByNeighbourCount
        Dim NeighbourSurveySequence As cNeighbourSurveySequence
        Dim RadialCalculator As cSpatialSimulationJobByRadialDistance
        Dim RadialSurveySequence As cRadialDistanceSurveySequence


        If mDataAgentSpatial.SourceFileType = eSourceFileType.eftCSV Then
            PrimaryOutputStringBuilder = New System.Text.StringBuilder()
            PrimaryOutput = New TreeCreeper03.cStringBuilder(PrimaryOutputStringBuilder)
            SecondaryOutput = GetDetailsReportOutputFile()
        Else
            Throw New Exception("Source file type is undefined!")
        End If

        LabelProgress.Text = "Starting simulation..."

        NumberOfRandoms = CInt(Me.UpDownNumberOfRandomRuns.Value)
        DoRandomiseWithinGroupsOnly = Me.OptionBlockRandom.Checked
        If Me.OptionDistanceRandom.Checked Then
            DistanceLimitedRandomisation = Me.UpDownRandomDistanceLimit.Value
        Else
            DistanceLimitedRandomisation = 0
        End If
        RandomisedPlantLists = GetCollectionOfRandomisedPlantLists(NumberOfRandoms, DoRandomiseWithinGroupsOnly, DistanceLimitedRandomisation)


        If RadioDoOrganizeByLocation.Checked Then
            ' by location
            DetailResultRowComposition = eDetailResultRowComposition.edrrcRowContainsResultsWithConstantLocation
        Else
            ' by plant id
            DetailResultRowComposition = eDetailResultRowComposition.edrrcRowContainsResultsWithConstantPlantIdentity
        End If


        Select Case True
            Case TabControl1.SelectedTab Is TabPage1
                RadialSurveySequence = GetRadialSurveySequence()
                RadialCalculator = New cSpatialSimulationJobByRadialDistance(mStudy)
                RadialCalculator.DoCalculation(RadialSurveySequence, RandomisedPlantLists, Me, PrimaryOutput, DetailResultRowComposition, SecondaryOutput)

            Case TabControl1.SelectedTab Is TabPage2
                NeighbourSurveySequence = GetNeighbourSurveySequence()
                NeighbourhoodCalculator = New cSpatialSimulationJobByNeighbourCount(mStudy)
                NeighbourhoodCalculator.DoCalculation(NeighbourSurveySequence, RandomisedPlantLists, Me, PrimaryOutput, DetailResultRowComposition, SecondaryOutput)
        End Select

        LabelProgress.Text = ""


        ' show the summary details in different textbox form
        Dim ResultsSummaryForm As fSpatialResultsSummary
        ResultsSummaryForm = New fSpatialResultsSummary()
        ResultsSummaryForm.Show()
        ResultsSummaryForm.ResultsSummaryTextBox.Text = PrimaryOutputStringBuilder.ToString


        If Not SecondaryOutput Is Nothing Then
            SecondaryOutput.Dispose()
        End If
        PrimaryOutput.Dispose()


    End Sub

    Private Function GetRadialSurveySequence() As cRadialDistanceSurveySequence

        Dim Limit(4) As Double
        Dim StepCount As Integer
        Dim Survey As cRadialDistanceSurveySequence

        Limit(1) = CDbl(UpDownInnerRadiusLowerLimit.Value)
        Limit(2) = CDbl(UpDownInnerRadiusUpperLimit.Value)
        Limit(3) = CDbl(UpDownOuterRadiusLowerLimit.Value)
        Limit(4) = CDbl(UpDownOuterRadiusUpperLimit.Value)

        StepCount = CInt(Me.UpDownRadiusStepCount.Value)

        Debug.Assert(StepCount >= 0)
        'Debug.Assert(Limit(1) <= Limit(2))
        'Debug.Assert(Limit(3) <= Limit(4))

        If RadioIncreaseOuterRadii.Checked Then
            Survey = New cRadialDistanceSurveySequenceOuterIncreasing(Limit(1), Limit(3), Limit(4), StepCount)
        Else
            'Should this be three or four?
            Survey = New cRadialDistanceSurveySequenceInnerIncreasing(Limit(1), Limit(2), Limit(4), StepCount)
        End If

        Return Survey

    End Function

    Private Function GetNeighbourSurveySequence() As cNeighbourSurveySequence

        Dim Limit(4) As Integer
        Dim StepSize As Integer
        Dim Survey As cNeighbourSurveySequence

        Limit(1) = CInt(UpdownNeighboursInnerLowerLimit.Value)
        Limit(2) = CInt(UpdownNeighboursInnerUpperLimit.Value)
        Limit(3) = CInt(UpdownNeighboursOuterLowerLimit.Value)
        Limit(4) = CInt(UpdownNeighboursOuterUpperLimit.Value)

        StepSize = CInt(UpDownNeighbourSteps.Value)

        Debug.Assert(StepSize >= 1)
        Debug.Assert(Limit(1) <= Limit(2))
        Debug.Assert(Limit(3) <= Limit(4))

        If RadioIncreaseOuterNeighbours.Checked Then
            Survey = New cNeighbourSurveySequenceOuterIncreasing(Limit(1), Limit(3), Limit(4), StepSize)
        Else
            'Should this be three or four?
            Survey = New cNeighbourSurveySequenceInnerIncreasing(Limit(1), Limit(2), Limit(4), StepSize)
        End If

        Return Survey

    End Function

    Private Function GetDetailsReportOutputFile() As IResultsTable

        Dim DetailsFileWriter As IResultsTable
        Dim DoWriteDetailsToFile As Boolean
        Dim SaveFileDialog As SaveFileDialog
        Dim SaveFileName As String

        DetailsFileWriter = Nothing

        DoWriteDetailsToFile = Me.CheckDoWriteDetailsToFile.Checked
        If DoWriteDetailsToFile Then
            SaveFileDialog = New SaveFileDialog
            If TabControl1.SelectedTab Is TabPage1 Then
                SaveFileDialog.FileName = "RadiusAnalysisDetails.txt"
            Else
                SaveFileDialog.FileName = "NeighbourAnalysisDetails.txt"
            End If
            SaveFileDialog.Title = "File for writing output details"
            If SaveFileDialog.ShowDialog = Windows.Forms.DialogResult.OK Then
                SaveFileName = SaveFileDialog.FileName
                DetailsFileWriter = New TreeCreeper03.cStreamWriter(SaveFileName)
            Else
                ' what now? Exit the job. A cancel is a cancel that propagates up the whole way.
                'Return Nothing. This should be treated as a cancellation
            End If
        End If

        Return DetailsFileWriter

    End Function

    Private Function GetCollectionOfRandomisedPlantLists(ByVal NumberOfRandoms As Integer, ByVal RandomizeWithinGroupsOnly As Boolean, Optional ByVal RandomiseDistanceLimit As Double = 0) As Collection

        Dim RandomisedPlantLists As Collection
        Dim BasePlantList As IPlantList
        Dim RandomIndex As Integer
        Dim FilteredPlantList As IPlantList

        Debug.Assert(NumberOfRandoms >= 0)

        RandomisedPlantLists = New Collection
        If NumberOfRandoms > 0 Then
            BasePlantList = mStudy.PlantList
            For RandomIndex = 1 To NumberOfRandoms
                If RandomizeWithinGroupsOnly Then
                    FilteredPlantList = mStudy.NewPlantListByFullCoordinatePermutationPerGroup()
                Else
                    If RandomiseDistanceLimit > 0 Then
                        FilteredPlantList = mStudy.NewPlantListByDistanceLimitedCoordinatePermutation(RandomiseDistanceLimit)
                    Else
                        FilteredPlantList = mStudy.NewPlantListByFullCoordinatePermutation()
                    End If
                    If Me.CheckDrawRandomisedMaps.Checked Then
                        With New fMap(FilteredPlantList) ', mColouringList)
                            .Display("Random arrangement, number " & RandomIndex.ToString & " of " & NumberOfRandoms.ToString)
                        End With
                    End If
                End If
                RandomisedPlantLists.Add(FilteredPlantList)
            Next
        End If

        Return RandomisedPlantLists

    End Function



#Region "Methods which respond to user interaction to change settings and configurations"

    Private Sub RefreshRadialStepSizeLabel()

        'Different up-down controls trigger a redisplay of the step size label (on tab#1 of 2)

        If Not Visible Then Exit Sub

        Dim Sequence As cRadialDistanceSurveySequence
        Dim NumberOfSteps As Integer
        Dim StepSize As Double


        'If RadioIncreaseOuterRadii.Checked Then
        'NewUpperLimit = UpDownOuterRadiusUpperLimit.Value
        'Else
        'NewUpperLimit = UpDownInnerRadiusUpperLimit.Value
        'End If

        Sequence = GetRadialSurveySequence()

        NumberOfSteps = Sequence.CountOfSteps - 1
        StepSize = Sequence.StepSize
        UpDownRadiusStepCount.Value = NumberOfSteps
        Me.LabelRadialStepSize.Text = "steps of " & StepSize

        'If RadioIncreaseOuterRadii.Checked Then
        '    Me.UpDownOuterRadiusLowerLimit.Enabled = _
        '        (NumberOfSteps > 0) Or Me.UpDownOuterRadiusLowerLimit.Value >= Me.UpDownOuterRadiusUpperLimit.Value
        'Else
        '    Me.UpDownInnerRadiusUpperLimit.Enabled = _
        '        (NumberOfSteps > 0) Or Me.UpDownInnerRadiusUpperLimit.Value <= Me.UpDownInnerRadiusLowerLimit.Value
        'End If

    End Sub

    Private Sub RefreshNeighbourStepCountLabel()

        'Different up-down controls trigger a redisplay of the neighbour count label (on tab#2 of 2)

        Dim LowerLimit As Integer
        Dim UpperLimit As Integer
        Dim IncrementOuter As Boolean
        Dim Range As Integer
        Dim NumberOfSteps As Integer
        Dim StepSize As Double

        IncrementOuter = RadioIncreaseOuterNeighbours.Checked

        If IncrementOuter Then
            LowerLimit = CInt(UpdownNeighboursOuterLowerLimit.Value)
            UpperLimit = CInt(UpdownNeighboursOuterUpperLimit.Value)
        Else
            LowerLimit = CInt(UpdownNeighboursInnerLowerLimit.Value)
            UpperLimit = CInt(UpdownNeighboursInnerUpperLimit.Value)
        End If

        StepSize = CInt(UpDownNeighbourSteps.Value)

        Range = UpperLimit - LowerLimit
        If Range > 0 Then
            If StepSize > 0 Then
                NumberOfSteps = CType((Range / StepSize) + 1, Integer)
            End If
        End If

        If NumberOfSteps = 0 Then
            Me.LabelNeighbourStepCount.Text = "in " & NumberOfSteps & " steps"
        Else
            Me.LabelNeighbourStepCount.Text = "in " & NumberOfSteps & " steps of: "
        End If


    End Sub

#End Region
    
#Region "Control events"

    Private Sub Go_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonDo.Click
        Try
            ButtonDo.Enabled = False
            DoSimulation()

        Finally
            ButtonDo.Enabled = True

        End Try
    End Sub

    Private Sub UpDownInnerRadiusUpperLimit_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles UpDownInnerRadiusUpperLimit.ValueChanged
        UpDownOuterRadiusUpperLimit.Minimum = UpDownInnerRadiusUpperLimit.Value
        RefreshRadialStepSizeLabel()
    End Sub

    Private Sub UpDownRadiusStepCount_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles UpDownRadiusStepCount.ValueChanged
        RefreshRadialStepSizeLabel()
    End Sub

    Private Sub UpDownOuterRadiusUpperLimit_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles UpDownOuterRadiusUpperLimit.ValueChanged
        RefreshRadialStepSizeLabel()
    End Sub

    Private Sub UpDownInnerRadiusLowerLimit_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles UpDownInnerRadiusLowerLimit.ValueChanged
        RefreshRadialStepSizeLabel()
    End Sub

    Private Sub UpDownOuterRadiusLowerLimit_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles UpDownOuterRadiusLowerLimit.ValueChanged
        RefreshRadialStepSizeLabel()
    End Sub

    Private Sub RadioIncreaseInnerRadii_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles RadioIncreaseInnerRadii.CheckedChanged
        UpDownInnerRadiusUpperLimit.Enabled = RadioIncreaseInnerRadii.Checked
        RefreshRadialStepSizeLabel()
    End Sub

    Private Sub RadioIncreaseOuterRadii_CheckedChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles RadioIncreaseOuterRadii.CheckedChanged
        UpDownOuterRadiusLowerLimit.Enabled = RadioIncreaseOuterRadii.Checked
        RefreshRadialStepSizeLabel()
    End Sub

    Private Sub UpdownNeighboursInnerLowerLimit_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles UpdownNeighboursInnerLowerLimit.ValueChanged
        RefreshNeighbourStepCountLabel()
    End Sub

    Private Sub UpdownNeighboursInnerUpperLimit_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles UpdownNeighboursInnerUpperLimit.ValueChanged
        RefreshNeighbourStepCountLabel()
    End Sub

    Private Sub UpdownNeighboursOuterLowerLimit_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles UpdownNeighboursOuterLowerLimit.ValueChanged
        RefreshNeighbourStepCountLabel()
        UpdownNeighboursOuterUpperLimit.Minimum = UpdownNeighboursOuterLowerLimit.Value
    End Sub

    Private Sub UpdownNeighboursOuterUpperLimit_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles UpdownNeighboursOuterUpperLimit.ValueChanged
        RefreshNeighbourStepCountLabel()
        UpdownNeighboursOuterLowerLimit.Maximum = UpdownNeighboursOuterUpperLimit.Value
    End Sub

    Private Sub UpDownNeighbourSteps_ValueChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles UpDownNeighbourSteps.ValueChanged
        RefreshNeighbourStepCountLabel()
    End Sub

    Private Sub RadioIncreaseInnerNeighbours_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadioIncreaseInnerNeighbours.CheckedChanged
        UpdownNeighboursInnerUpperLimit.Enabled = RadioIncreaseInnerNeighbours.Checked
        RefreshNeighbourStepCountLabel()
    End Sub

    Private Sub RadioIncreaseOuterNeighbours_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadioIncreaseOuterNeighbours.CheckedChanged
        UpdownNeighboursOuterLowerLimit.Enabled = RadioIncreaseOuterNeighbours.Checked
        RefreshNeighbourStepCountLabel()
    End Sub

    Private Sub ButtonExit_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonExit.Click
        Me.Close()
    End Sub

#End Region

    Private Sub fSpatialBatchAnalysis_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.UpDownNeighbourSteps.Minimum = 0
        Me.UpDownRadiusStepCount.Minimum = 0
    End Sub

    Public Sub New()

        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.

    End Sub

    Private Sub OptionDistanceRandom_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OptionDistanceRandom.CheckedChanged

        Me.UpDownRandomDistanceLimit.Enabled = OptionDistanceRandom.Checked

    End Sub



End Class